home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
wdj0697.zip
/
SDKANN.ZIP
/
SOURCE.ZIP
/
PLAYBACK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-10
|
12KB
|
407 lines
#include "playback.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/**** WDJ_Pbh_Event
This structure describes an individual journal playback hook event (a
mouse or keyboard message). The functions here create, manipulate, and
playback linked lists of such events (the linked list is not visible via
the API).
****/
typedef struct WDJ_Pbh_Event
{
struct WDJ_Pbh_Event *Next;
UINT Message;
UINT Low;
UINT High;
DWORD Delay;
} WDJ_Pbh_Event;
/**** WDJ_Pbh_List
This structure is the head and tail pointer for a linked list of journal
playback hook events. An opaque pointer to this structure is returned
and accepted by the API.
****/
typedef struct WDJ_Pbh_List
{
WDJ_Pbh_Event *First;
WDJ_Pbh_Event *Last;
HINSTANCE Instance;
} WDJ_Pbh_List;
#define NEW(type) (type *)malloc(sizeof(type))
static WDJ_Pbh_List *InProgress;
static WDJ_Pbh_Event *NextEvent;
static WNDPROC NotifyFunc;
static HWND NotifyWindow;
static UINT NotifyMessage;
static WPARAM NotifyParam1;
static LPARAM NotifyParam2;
static EVENTMSG Event;
static DWORD EventDelay;
static DWORD EventDelayStart;
static HHOOK OldHook;
/* forward declare the lowest-level playback function */
static int StartPlayback(WDJ_Pbh Handle, WNDPROC Callback,
HWND W, UINT M, WPARAM p1, LPARAM p2);
/* and the hook function itself */
LRESULT CALLBACK _export PlayBackHook(int Code,
WPARAM Param1, LPARAM Param2);
static UINT KeyId(UINT VirtualKey)
{
return (VirtualKey&0x00FF) | (MapVirtualKey(VirtualKey, 0)<<8);
}
/* Create - Create the initial linked-list of events */
WDJ_Pbh WDJ_Pbh_Create(HINSTANCE Instance)
{
/* Allocate new list */
WDJ_Pbh_List *List = NEW(WDJ_Pbh_List);
/* if we got the memory */
if(List)
{
/* initialize ptrs to NULL */
List->First = 0;
List->Last = 0;
List->Instance = Instance;
}
/* return handle, or NULL if failed */
return (WDJ_Pbh)List;
}
/* AppendRaw - lowest-level function to add event to list */
int WDJ_Pbh_AppendRaw(WDJ_Pbh Handle, UINT Message, UINT Low,
UINT High, DWORD Delay)
{
/* turn handle into event list */
WDJ_Pbh_List *List = (WDJ_Pbh_List *)Handle;
/* if we were handed a non-null ptr */
if(List)
{
/* allocate a new event record */
WDJ_Pbh_Event *Event = NEW(WDJ_Pbh_Event);
/* if we got the memory */
if(Event)
{
/* Next is NULL, since we are last in linked list */
Event->Next = 0;
/* raw copy -- caller better know what he's doing */
Event->Message = Message;
Event->Low = Low;
Event->High = High;
//??????
Event->Delay = 50;
// Event->Delay = Delay;
/* link new event into list */
if(!List->First)
List->First = List->Last = Event;
else
{
List->Last->Next = Event;
List->Last = Event;
}
return TRUE;
}
}
/* couldn't get memory for new event */
return FALSE;
}
/* AppendChar - generate up-down strokes for a character */
int WDJ_Pbh_AppendChar(WDJ_Pbh Handle, int Char)
{
/* turn handle into event list */
WDJ_Pbh_List *List = (WDJ_Pbh_List *)Handle;
/* if we were handed a non-null ptr */
if(List)
{
UINT Vchar = VkKeyScan(Char&0x00FF);
int Shift = (Vchar&0x0100) != 0;
int Sys = 0; /* assume it will not be sys key */
if((Char&WDJ_PBH_ALT) && !(Char&WDJ_PBH_CTL))
Sys += 4; /* +4 turns WM_KEY?? into WM_SYSKEY?? */
if(Char & WDJ_PBH_ALT)
WDJ_Pbh_AppendRaw(Handle, WM_SYSKEYDOWN, KeyId(VK_MENU), 1, 0);
if(Char & WDJ_PBH_CTL)
WDJ_Pbh_AppendRaw(Handle, WM_KEYDOWN, KeyId(VK_CONTROL), 1, 0);
if(Shift)
WDJ_Pbh_AppendRaw(Handle, WM_KEYDOWN, KeyId(VK_SHIFT), 1, 0);
WDJ_Pbh_AppendRaw(Handle, WM_KEYDOWN+Sys, KeyId(Vchar), 1, 0);
WDJ_Pbh_AppendRaw(Handle, WM_KEYUP+Sys, KeyId(Vchar), 1, 0);
if(Shift)
WDJ_Pbh_AppendRaw(Handle, WM_KEYUP, KeyId(VK_SHIFT), 1, 0);
if(Char & WDJ_PBH_CTL)
WDJ_Pbh_AppendRaw(Handle, WM_KEYUP, KeyId(VK_CONTROL), 1, 0);
if(Char & WDJ_PBH_ALT)
WDJ_Pbh_AppendRaw(Handle, WM_KEYUP, KeyId(VK_MENU), 1, 0);
return TRUE;
}
return FALSE;
}
/* AppendString - do multiple chars */
int WDJ_Pbh_AppendString(WDJ_Pbh Handle, const char *String)
{
/* turn handle into event list */
WDJ_Pbh_List *List = (WDJ_Pbh_List *)Handle;
/* if we were handed a non-null ptr */
if(List && String)
{
while(*String)
WDJ_Pbh_AppendChar(Handle, *String++);
}
return FALSE;
}
/* PlayCallback - Playback events, then call callback function */
int WDJ_Pbh_PlayCallback(WDJ_Pbh Handle, WNDPROC Callback,
HWND W, UINT M, WPARAM p1, LPARAM p2)
{
return StartPlayback(Handle, Callback, W, M, p1, p2);
}
/* PumpCallback - Playback events, then call do message pump */
int WDJ_Pbh_PumpCallback(WDJ_Pbh Handle, WNDPROC Callback,
HWND W, UINT M, WPARAM p1, LPARAM p2)
{
MSG Message;
int Result;
Result = StartPlayback(Handle, Callback, W, M, p1, p2);
if(Result == FALSE)
return FALSE;
/* pump messages until none left. Presumably all
* events will be played back by then. Note: this
* works perfectly only if the app being pumped
* was using a loop just like this one.
*/
while(InProgress)
while(PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
if(Message.message == WM_QUIT)
{
PostQuitMessage(0);
return TRUE;
}
else
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return TRUE;
}
int WDJ_Pbh_String(HINSTANCE Instance, const char *String)
{
int Char;
int Alt;
WDJ_Pbh Handle;
Handle = WDJ_Pbh_Create(Instance);
if(!Handle || !String)
return FALSE;
while((Char = *String++) != '\0')
{
Alt = FALSE;
if(Char == '^')
{
Char = *String++;
if(Char && Char != '^')
Alt = TRUE;
}
if(Char)
WDJ_Pbh_AppendChar(Handle, Char | (Alt?WDJ_PBH_ALT:0));
}
WDJ_Pbh_Pump(Handle);
WDJ_Pbh_Destroy(Handle);
return TRUE;
}
/* StartPlayback - Start hook, remember what func to call at end */
static int StartPlayback(WDJ_Pbh Handle, WNDPROC Callback,
HWND W, UINT M, WPARAM p1, LPARAM p2)
{
if(InProgress)
OutputDebugString("Playback already in progress!\n");
if(InProgress || Handle == NULL)
return FALSE;
else
{
InProgress = (WDJ_Pbh_List *)Handle;
if(InProgress == NULL || InProgress->First == NULL)
return FALSE;
NextEvent = InProgress->First;
}
NotifyFunc = Callback;
NotifyWindow = W;
NotifyMessage = M;
NotifyParam1 = p1;
NotifyParam2 = p2;
//??? get initial state of up/down keys here!
OldHook = SetWindowsHookEx(WH_JOURNALPLAYBACK,
PlayBackHook, InProgress->Instance, NULL);
return OldHook != NULL;
}
/* Destroy - free list and recover memory */
int WDJ_Pbh_Destroy(WDJ_Pbh Handle)
{
WDJ_Pbh_List *List = (WDJ_Pbh_List *)Handle;
/* if looks like valid handle */
if(List)
{
WDJ_Pbh_Event *Event, *Next;
Event = List->First;
while(Event)
{
Next = Event->Next;
free(Event);
Event = Next;
}
return TRUE;
}
return FALSE;
}
int WDJ_Pbh_Play(WDJ_Pbh Handle)
{
return WDJ_Pbh_PlayCallback(Handle, 0, 0, 0, 0, 0);
}
int WDJ_Pbh_Pump(WDJ_Pbh Handle)
{
return WDJ_Pbh_PumpCallback(Handle, 0, 0, 0, 0, 0);
}
static void TerminatePlayback(void)
{
OutputDebugString("TerminatePlayback\n");
UnhookWindowsHookEx(OldHook);
OutputDebugString("unhooked\n");
OutputDebugString("freeed\n");
Event.message = 0;
InProgress = 0;
if(NotifyFunc)
NotifyFunc(NotifyWindow, NotifyMessage, NotifyParam1, NotifyParam2);
OutputDebugString("notified\n");
}
static int GetNextEvent(void)
{
/* if input queue is empty */
if(!NextEvent)
return FALSE;
Event.message = NextEvent->Message;
Event.paramL = NextEvent->Low;
Event.paramH = NextEvent->High;
Event.time = GetTickCount();
EventDelay = NextEvent->Delay;
EventDelayStart = Event.time;
NextEvent = NextEvent->Next;
return TRUE;
}
const char *Grok(UINT Msg)
{
static char Buffer[128];
switch(Msg)
{
case WM_SYSKEYDOWN : return "WM_SYSKEYDOWN";
case WM_KEYDOWN : return "WM_KEYDOWN";
case WM_SYSKEYUP : return "WM_SYSKEYUP";
case WM_KEYUP : return "WM_KEYUP";
default:
wsprintf(Buffer, "0x%04X (%d)", Msg, Msg);
return Buffer;
}
}
LRESULT CALLBACK _export PlayBackHook(int Code,
WPARAM Param1, LPARAM Param2)
{
long Result = 0;
int CallNextHook = FALSE;
switch(Code)
{
case HC_GETNEXT :
{
char Buffer[256];
/* first code after installing hook is HC_GETNEXT,
* hence, we use Event.message as a flag that says
* we need to prime the pump. This way, if Windows
* changes someday to issue HC_SKIP first, the code
* here still works.
*/
if(Event.message == 0)
GetNextEvent();
//???
// Event.time = GetTickCount();
#if 0
wsprintf(Buffer, "HC_GETNEXT m='%s', l=%d, h=%d, time=%ld D=%ld\n",
Grok(Event.message), Event.paramL, Event.paramH,
Event.time, EventDelay);
OutputDebugString( Buffer );
#endif
*(EVENTMSG*)Param2 = Event;
//??? return EventDelay;
{
DWORD Elapsed = GetTickCount() - EventDelayStart;
if(Elapsed >= EventDelay)
return 0;
else
return EventDelay - Elapsed;
}
}
case HC_SKIP :
//OutputDebugString( "HC_SKIP\n");
if(!GetNextEvent())
TerminatePlayback();
break;
case HC_SYSMODALOFF :
OutputDebugString( "HC_SYSMODALOFF\n");
TerminatePlayback();
case HC_SYSMODALON :
default :
OutputDebugString( "HC_SYSMODALON, default\n");
CallNextHook = TRUE;
}
if(CallNextHook)
{
OutputDebugString( "Call that next hook!\n" );
Result = CallNextHookEx(OldHook, Code, Param1, Param2);
}
return Result;
}